package pool;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

public class ThreadPool {

    class Worker extends Thread {

        /**
         * 任务
         */
        private Runnable task;

        public Worker(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            // 执行分配的任务和队列中的任务
            while (task != null || (task = workQueue.poll(keepAliveTime, unit)) != null) {
                try {
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    task = null;
                }
            }
            // 超时没有任务添加则回收核心线程外的线程
            synchronized (workers) {
                if (workers.size() > corePoolSize) {
                    workers.remove(this);
                    this.interrupt();
                }
            }
        }

    }

    /**
     * 工作线程
     */
    private final HashSet<Worker> workers;


    /**
     * 核心池大小
     */
    private final Integer corePoolSize;

    /**
     * 最大池大小
     */
    private final Integer maximumPoolSize;

    /**
     * 存活时间
     */
    private final Long keepAliveTime;

    /**
     * 时间单位
     */
    private final TimeUnit unit;

    /**
     * 任务队列
     */
    private final BlockingQueue<Runnable> workQueue;

    /**
     * 线程工厂
     */
    private final ThreadFactory threadFactory;

    /**
     * 拒绝策略
     */
    private final RejectedExecutionHandler<Runnable> handler;

    public ThreadPool(Integer corePoolSize, Integer maximumPoolSize, long keepAliveTime, TimeUnit unit, Integer queueCapacity, ThreadFactory threadFactory, RejectedExecutionHandler<Runnable> handler) {
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.unit = unit;
        this.keepAliveTime = keepAliveTime;
        this.workers = new HashSet<>(maximumPoolSize);
        this.workQueue = new BlockingQueue<>(queueCapacity);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

    /**
     * 执行任务
     *
     * @param task 任务
     */
    public void execute(Runnable task) {
        synchronized (workers) {
            // 1.判断核心线程数量未满
            // 2.判断任务队列已满且最大线程数量未满
            // 3.创建线程运行任务
            if (workers.size() < corePoolSize || (workQueue.isFull() && workers.size() < maximumPoolSize)) {
                Worker worker = new Worker(task);
                worker.setName(threadFactory.newThread(task).getName());
                workers.add(worker);
                worker.start();
            } else {
                // 加入任务队列，已满则执行拒绝策略
                workQueue.tryPut(handler, task);
            }
        }
    }

}
